/****************************************************************************
 *  QLyrics - A simple lyrics viewer.                                       *
 *  Copyright (C) 2008  hsys <hanshuiys@gmail.com>                          *
 *                                                                          *
 *  This program is free software; you can redistribute it and/or modify    *
 *  it under the terms of the GNU General Public License as published by    *
 *  the Free Software Foundation; either version 3 of the License, or       *
 *  (at your option) any later version.                                     *
 *                                                                          *
 *  This program is distributed in the hope that it will be useful,         *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 *  GNU General Public License for more details.                            *
 *                                                                          *
 *  You should have received a copy of the GNU General Public License       *
 *  along with this program; if not, write to the Free Software Foundation, *
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA       *
 ****************************************************************************/

#include "lyricswindow.h"
#include <QMouseEvent>
#include <QMenu>
#include <QMessageBox>
#include <QProcess>
#include "configmanager.h"
#include "lyricsmanager.h"
#include "player.h"
#include "configwindow.h"
#include "lyricsnormalpanel.h"
#include "lyricslayeredpanel.h"
#include "lyricsdownloadwindow.h"

LyricsWindow::LyricsWindow(QWidget* parent) : QMainWindow(parent) {
    ConfigManager* cfg = ConfigManager::getInstance();
    Player* player = Player::getInstance();
    LyricsManager* mgr = LyricsManager::getInstance();

    m_panel = NULL;

    // set window flags
    setWindowIcon(QIcon(":/res/qlyrics.png"));
    setMouseTracking(true);
    restoreGeometry(cfg->value("Window/Geometry").toByteArray());
    createMenu();
    reloadWindowStyle();

    // load lyrics panel
    m_mouseButton = Qt::NoButton;
    reloadPanel();

    // connect signals
    connect(player, SIGNAL(exit()), SLOT(close()));
    connect(player, SIGNAL(configure()), SLOT(showConfigWindow()));
    connect(mgr, SIGNAL(signalMultiChoice(LyricsJob*)), SLOT(showDownloadWindow(LyricsJob*)));
};

LyricsWindow::~LyricsWindow() {
    ConfigManager* cfg = ConfigManager::getInstance();
    cfg->setValue("Window/Geometry", saveGeometry());
};

void LyricsWindow::reloadWindowStyle() {
    ConfigManager* cfg = ConfigManager::getInstance();
    //Qt::WindowFlags flag = windowFlags() | Qt::Tool;
    Qt::WindowFlags flag = Qt::Tool;

    if (cfg->value("Window/Frameless", true).toBool()) {
        flag |= Qt::FramelessWindowHint;
    } else {
        flag &= ~Qt::FramelessWindowHint;
    };
    if (cfg->value("Window/OnTop", true).toBool()) {
        flag |= Qt::WindowStaysOnTopHint;
    } else {
        flag &= ~Qt::WindowStaysOnTopHint;
    };
    setWindowFlags(flag);
    //setAttribute(Qt::WA_NoSystemBackground);
    show();
    //setAlphaChannel();
};

void LyricsWindow::setAlphaChannel() {
#if 0
    ConfigManager* cfg = ConfigManager::getInstance();
if defined(_OS_WIN32_) || defined(Q_OS_WIN32)
    //SetWindowLong(winId(), GWL_EXSTYLE,
    //    GetWindowLong(winId(), GWL_EXSTYLE) | WS_EX_LAYERED);

    /*if (cfg->contains("Window/BackgroundImage")) {
        QImage image(cfg->value("Window/BackgroundImage", QString()).toString());
        if (!image.isNull()) {
            image = image.scaled(size());
            image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
            //QPixmap pix = QPixmap::fromImage(image);

            HBITMAP bmp = QPixmap::fromImage(image).toWinHBITMAP(QPixmap::PremultipliedAlpha);
            HDC hDC = CreateCompatibleDC(NULL);
            SelectObject(hDC, bmp);

            SIZE sz = {image.width(), image.height()};
            POINT ptSource = {0};
            BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };

            UpdateLayeredWindow(winId(), NULL, NULL, &sz, hDC,
                &ptSource, 0, &bf, ULW_ALPHA);

            DeleteObject(bmp);
            DeleteDC(hDC);
        };
    } else {
    *//*
        setWindowOpacity(cfg->value("Window/Opacity", 80).toInt() / 100.0);
        SetLayeredWindowAttributes(winId(),
            RGB(0, 0, 0),
            //cfg->value("Style/BgColor", Qt::black).value<QColor>().rgb(),
            0xff,
            LWA_COLORKEY);
*/

    //};

    /*if (m_panel != NULL) {
        SIZE sz = {rect().width(), rect().height()};
        POINT ptSource = {0};
        BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
        HDC hDC = m_panel->getDC();
        HDC hDC1 = CreateCompatibleDC(hDC);

        UpdateLayeredWindow(parentWidget()->winId(), NULL, NULL, &sz, hDC1,
            &ptSource, 0, &bf, ULW_ALPHA);
        m_panel->releaseDC(hDC);
        DeleteDC(hDC1);
    };*/
 else
#endif
    ConfigManager* cfg = ConfigManager::getInstance();
    setWindowOpacity(cfg->value("Window/Opacity", 80).toInt() / 100.0);
};

void LyricsWindow::createMenu() {
    LyricsManager* mgr = LyricsManager::getInstance();

    QMenu* downloadMenu = new QMenu(tr("&Download lyrics"), this);
    for (LyricsManager::const_iterator px = mgr->begin() + 1; px != mgr->end(); ++px) {
        QAction* act = new QAction((*px)->getProviderName(), this);
        act->setData(int(px - mgr->begin()));
        connect(act, SIGNAL(triggered()), SLOT(downloadLyrics()));
        downloadMenu->addAction(act);
    };

    QAction *actRefresh = new QAction(tr("&Refresh"), this);
    connect(actRefresh, SIGNAL(triggered()), mgr, SLOT(reloadLyrics()));
    QAction *actEditLrc = new QAction(tr("&Edit lyrics..."), this);
    connect(actEditLrc, SIGNAL(triggered()), SLOT(runLyricsEditor()));
    QAction *actLrcProp = new QAction(tr("&Lyrics properties..."), this);
    connect(actLrcProp, SIGNAL(triggered()), SLOT(showLyricsProp()));
    QAction *actConf = new QAction(tr("&Configure..."), this);
    connect(actConf, SIGNAL(triggered()), this, SLOT(showConfigWindow()));
    QAction *actAbout = new QAction(tr("&About..."), this);
    connect(actAbout, SIGNAL(triggered()), SLOT(showAboutWindow()));
    QAction *actExit = new QAction(tr("E&xit"), this);
    connect(actExit, SIGNAL(triggered()), SLOT(close()));

    m_popupMenu = new QMenu(this);
    m_popupMenu->addMenu(downloadMenu);
    m_popupMenu->addAction(actRefresh);
    m_popupMenu->addSeparator();
    m_popupMenu->addAction(actEditLrc);
    m_popupMenu->addAction(actLrcProp);
    m_popupMenu->addSeparator();
    m_popupMenu->addAction(actConf);
    m_popupMenu->addSeparator();
    m_popupMenu->addAction(actAbout);
    m_popupMenu->addAction(actExit);
};

void LyricsWindow::downloadLyrics() {
    QAction* act = qobject_cast<QAction*>(sender());
    if (!act)
        return;

    Player* player = Player::getInstance();
    if (player->getStatus() == Player::Idle) {
        QMessageBox::information(this, tr("Download Lyrics"), tr("No currently playing track."));
    };
    LyricsManager* mgr = LyricsManager::getInstance();
    mgr->search(player->getTrack(), act->data().toInt());
};

void LyricsWindow::runLyricsEditor() {
    LyricsManager* mgr = LyricsManager::getInstance();
    ConfigManager* cfg = ConfigManager::getInstance();
    Player* player = Player::getInstance();
    QString progPath = cfg->value("Misc/LyricsEditor").toString();
    if (player->getStatus() == Player::Idle || mgr->getLyrics() == NULL) {
        QMessageBox::information(this, tr("Lyrics Editor"), tr("No currently playing track."));
    } else if (progPath.isEmpty()) {
        QMessageBox::information(this, tr("Lyrics Editor"), tr("No external lyrics editor."));
    } else if (!QProcess::startDetached(progPath, QStringList(mgr->getLyricsFilename()))) {
        QMessageBox::information(this, tr("Lyrics Editor"), tr("Failed to start external lyrics editor."));
    };
};

void LyricsWindow::showAboutWindow() {
    QMessageBox::about(this, tr("About QLyrics"), tr("<p><b>About QLyrics</b></p>" \
            "<p>A simple lyrics viewer.</p>"));
};

void LyricsWindow::showLyricsProp() {
    LyricsManager* mgr = LyricsManager::getInstance();
    Player* player = Player::getInstance();
    if (player->getStatus() == Player::Idle || mgr->getLyrics() == NULL) {
        QMessageBox::information(this, tr("Lyrics properties"), tr("No currently playing track."));
    } else {
        const Track& track = mgr->getLyrics()->getTrack();
        QMessageBox::information(this, tr("Lyrics properties"),
                                tr("<dl>"
                                    "<dt><strong>File name:</strong>"
                                    "<dd>%1"
                                    "<dt><strong>Artist:</strong>"
                                    "<dd>%2"
                                    "<dt><strong>Album:</strong>"
                                    "<dd>%3"
                                    "<dt><strong>Title:</strong>"
                                    "<dd>%4"
                                    "<dt><strong>Lines:</strong>"
                                    "<dd>%5"
                                    "</dl>")
                                .arg(mgr->getLyricsFilename(),
                                    track.artist,
                                    track.album,
                                    track.title,
                                    QString::number(mgr->getLyrics()->size())));
    };
};

void LyricsWindow::showConfigWindow() {
    ConfigWindow cfgWin(this);
    LyricsManager* mgr = LyricsManager::getInstance();
    connect(&cfgWin, SIGNAL(signalReloadWindow()), SLOT(reloadWindowStyle()));
    connect(&cfgWin, SIGNAL(signalReloadPanel()), SLOT(reloadPanel()));
    connect(&cfgWin, SIGNAL(signalReloadLyrics()), mgr, SLOT(reloadLyrics()));
    cfgWin.exec();
};

void LyricsWindow::showDownloadWindow(LyricsJob* job) {
    LyricsDownloadWindow dlWin(job, this);
    dlWin.exec();
};

void LyricsWindow::closeEvent(QCloseEvent* e) {
    e->accept();
    QApplication::quit();
};

void LyricsWindow::reloadPanel() {
    /*
    LyricsPanelManager* panelMgr = LyricsPanelManager::getInstance();
    ConfigManager* cfg = ConfigManager::getInstance();
    // this function can be called in constructor, so we have to check if previous panel exists
    m_panel = panelMgr->findPanel(cfg->value("Style/ScrollStyle").toString())->create(this);
    */
    if (m_panel != NULL)
        m_panel->deleteLater();
    //m_panel = new LyricsNormalPanel(this);
    m_panel = new LyricsLayeredPanel(this);
    //m_panel->show();
    setCentralWidget(m_panel);
    //m_panel = panelMgr->findPanel(cfg->value("Style/ScrollStyle").toString())->create(NULL);
    //m_panel->show();
};

void LyricsWindow::mousePressEvent(QMouseEvent* e) {
    // write down the mouse position and button status
    m_mousePos = e->pos();
    m_mouseButton = e->button();
};

void LyricsWindow::mouseMoveEvent(QMouseEvent* e) {
    const int WINDOW_EDGE_WIDTH = 5;
    switch (m_mouseButton) {
    case Qt::LeftButton:
        if (m_mouseOnRightEdge || m_mouseOnBottomEdge) {
            // this means resizing the window
            QSize s(m_mouseOnRightEdge ? e->x() - m_mousePos.x() : 0,
                    m_mouseOnBottomEdge ? e->y() - m_mousePos.y() : 0);
            s += size();
            if (s.height() > 0 && s.width() > 0) {
                resize(s);
                m_mousePos = e->pos();
            };
        } else {
            // this means moving the window
            move(e->globalPos() - m_mousePos);
        };
        break;
    case Qt::MidButton:
        break;
    case Qt::NoButton:
        // we need to change the mouse cursor in the edge of the window
        const QRect& r = rect();
        m_mouseOnRightEdge = qAbs(e->x() - r.right()) <= WINDOW_EDGE_WIDTH;
        m_mouseOnBottomEdge = qAbs(e->y() - r.bottom()) <= WINDOW_EDGE_WIDTH;
        if (m_mouseOnRightEdge && m_mouseOnBottomEdge) {
            setCursor(Qt::SizeFDiagCursor);
        } else if (m_mouseOnRightEdge) {
            setCursor(Qt::SizeHorCursor);
        } else if (m_mouseOnBottomEdge) {
            setCursor(Qt::SizeVerCursor);
        } else {
            setCursor(Qt::ArrowCursor);
        };
        break;
    };
};

void LyricsWindow::mouseReleaseEvent(QMouseEvent*) {
    m_mouseButton = Qt::NoButton;
};

void LyricsWindow::contextMenuEvent(QContextMenuEvent* e) {
    m_popupMenu->exec(e->globalPos());
};

void LyricsWindow::paintEvent(QPaintEvent* e) {
#if 0
    //e->ignore();
    //return;
    
    //static int flag = 0;
    ConfigManager* cfg = ConfigManager::getInstance();
    QPainter painter;
    // fill the background first
    if (painter.begin(this)) {
        painter.fillRect(e->rect(), QBrush(cfg->value("Style/BgColor", Qt::black).value<QColor>()));
//        painter.setCompositionMode(QPainter::CompositionMode_Source);
        //painter.fillRect(rect(), Qt::transparent);
        painter.end();
    };
    
    //    hide();
    //    QPixmap m = QPixmap::grabWindow(QApplication::desktop()->winId());
    //    show();
    //    painter.drawPixmap(rect(), m, rect());
    //    painter.setPen(Qt::white);
    //    painter.drawText(20, 20, QString::number(flag++));
#endif
};

